﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.IO;
using System.Xml;

namespace WpfHardCodedStringsFinder.Views
{
	/// <summary>
	/// Interaction logic for ReplacementWindow.xaml
	/// </summary>
	public partial class ReplacementWindow : Window
	{
		public string ProjectRootPath
		{
			get { return (string)GetValue(ProjectRootPathProperty); }
			set { SetValue(ProjectRootPathProperty, value); }
		}

		// Using a DependencyProperty as the backing store for ProjectRootPath.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty ProjectRootPathProperty =
			DependencyProperty.Register("ProjectRootPath", typeof(string), typeof(ReplacementWindow), new UIPropertyMetadata(string.Empty));

		public ReplacementWindow()
		{
			InitializeComponent();
			this.Loaded += new RoutedEventHandler(ReplacementWindow_Loaded);
		}

		void ReplacementWindow_Loaded(object sender, RoutedEventArgs e)
		{
			foreach (Window win in (Application.Current as App).Windows)
			{
				if (win is SelectProjectWindow)
				{
					this.DataContext = (win as SelectProjectWindow).SelectedProject;
					break;
				}
			}
		}

		private void btnProcess_Click(object sender, RoutedEventArgs e)
		{
			if (cmbResourceFile.SelectedItem == null)
			{
				MessageBox.Show("Please select resource file or create new", "", MessageBoxButton.OK, MessageBoxImage.Warning);
				return;
			}

			else if (lstView.ItemsSource != null && (lstView.ItemsSource as List<Entities.SeachedItem>).Where(x => x.IsProcess).Count() == 0)
			{
				MessageBox.Show("Please select one or mere string to move in resources", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
				return;
			}

			else if (lstView.ItemsSource != null && (lstView.ItemsSource as List<Entities.SeachedItem>).Count > 0)
			{
				List<Entities.SeachedItem> unprocessedItem = new List<Entities.SeachedItem>();
				Common.Entities.EmbeddedResources selectedResource = (cmbResourceFile.SelectedItem as Common.Entities.EmbeddedResources);

				foreach (Entities.SeachedItem item in lstView.ItemsSource)
				{
					StringBuilder codeFileData = new StringBuilder();

					if (item.IsProcess)
					{
						Common.FileUtility.MakeFileWritable(item.FullPath);
						bool excThrowned = false;
						using (StreamReader sr = new StreamReader(item.FullPath, Encoding.UTF8))
						{
							string readLine = string.Empty;
							while ((readLine = sr.ReadLine()) != null)
							{
								codeFileData.AppendLine(readLine);
							}

							if (codeFileData.Length < 10)
								continue;
						}

						int oldLenght = 0;
						int newLenght = 0;

						try
						{
							//Adding new string value to selected reources file(*.resx)
							AddNewStringValueToResource(selectedResource, item);

							//Read data that contains in resource designer file and fill special stringBuilder;
							StringBuilder designerData = null;
							string insertionData = string.Empty;
							string desinerFilePath = System.IO.Path.Combine(ProjectRootPath, string.Format(@"Properties/{0}.Designer.cs",
																			System.IO.Path.GetFileNameWithoutExtension(selectedResource.Name)));

							using (StreamReader designerReader = new StreamReader(desinerFilePath))
							{
								designerData = new StringBuilder(designerReader.ReadToEnd());
							}
							//make file writable and add properties wich will be related to *.resx file
							Common.FileUtility.MakeFileWritable(desinerFilePath);
							Common.FileUtility.ClearFileContent(desinerFilePath);
							using (StreamWriter designerWriter = new StreamWriter(desinerFilePath))
							{
								int indexOfLast = designerData.ToString().LastIndexOf('}');
								if (indexOfLast == -1)
									throw new InvalidOperationException("cannot find index of last '}' char");

								designerData = new StringBuilder(designerData.ToString().Remove(indexOfLast));
								indexOfLast = designerData.ToString().LastIndexOf('}');

								//Ctreate property value for designer file 
								StringBuilder propertiesData = new StringBuilder();
								propertiesData.AppendLine(string.Format("   public static string {0}", item.RenameValue));
								propertiesData.AppendLine("   {");
								propertiesData.AppendLine("     get");
								propertiesData.AppendLine("     {");
								propertiesData.AppendLine(string.Format("\t  return ResourceManager.GetString(\"{0}\", resourceCulture);", item.RenameValue));
								propertiesData.AppendLine("     }");
								propertiesData.AppendLine("   }");

								designerData.Insert(indexOfLast - 1, propertiesData.ToString());
								designerData.AppendLine("}");
								designerWriter.WriteLine(designerData.ToString());
								designerData.Clear();
								propertiesData.Clear();

								insertionData = string.Format("{0}.Properties.Resources.{1}", (DataContext as Common.Entities.DetailedProjectInfo).RootNamespace,
									item.RenameValue);
							}

							//work with C# project file for futher replace
							oldLenght = item.Value.Length;
							newLenght = insertionData.Length;

							codeFileData.Remove(item.BeginIndex, item.Value.Length);
							codeFileData.Insert(item.BeginIndex, insertionData);
							// Write new code file to it's palce on disk
							Common.FileUtility.ClearFileContent(item.FullPath);
							using (StreamWriter streamWriter = new StreamWriter(item.FullPath))
							{
								using (StringReader stringReader = new StringReader(codeFileData.ToString()))
								{
									string readLine = string.Empty;
									while ((readLine = stringReader.ReadLine()) != null)
									{
										streamWriter.WriteLine(readLine);
									}
								}
								codeFileData.Clear();
								codeFileData = null;
							}

							(lstView.ItemsSource as List<Entities.SeachedItem>).ForEach(new Action<Entities.SeachedItem>(si =>
							{
								si.BeginIndex = ((si.BeginIndex - oldLenght) + newLenght);
								si.EndIndex = ((si.EndIndex - oldLenght) + newLenght);
							}));

							System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(300));

							if (codeFileData != null && codeFileData.Length > 0)
							{
								codeFileData.Clear();
								codeFileData = null;
							}
						}
						catch (Exception ex)
						{
							excThrowned = true;
							item.FailReason = ex.Message;
							item.FailException = ex;
							unprocessedItem.Add(item);
						}

						if (excThrowned)
							continue;
					}
				}

				if (unprocessedItem.Count > 0)
				{
					if (MessageBox.Show("Errors occured while processed strings. Would you like to view it?", "Error", MessageBoxButton.YesNo, MessageBoxImage.Warning)
						== MessageBoxResult.Yes)
					{
					}
				}
				else
				{
					MessageBox.Show("Operation complete successfully", "Done", MessageBoxButton.OK, MessageBoxImage.Information);
				}
			}
		}

		private void AddNewStringValueToResource(Common.Entities.EmbeddedResources selectedResource, Entities.SeachedItem item)
		{
			if (selectedResource == null || item == null)
				throw new ArgumentNullException("Some of input parameters is null");

			XmlDocument resourceDocument = new XmlDocument();
			resourceDocument.Load(System.IO.Path.Combine(ProjectRootPath, selectedResource.Name));
			//Create new data node wich will be contain hardcoded string
			XmlElement dataElement = resourceDocument.CreateElement("data");
			XmlAttribute nameAttr = resourceDocument.CreateAttribute("name");
			nameAttr.Value = item.RenameValue;
			dataElement.Attributes.Append(nameAttr);
			XmlElement valueElement = resourceDocument.CreateElement("value");
			string oldVal = item.Value;
			string newVal = oldVal.Trim().Remove(0, 1);
			newVal = newVal.Remove(newVal.Length - 1, 1);
			valueElement.InnerText = newVal;
			XmlElement commentElement = resourceDocument.CreateElement("comment");
			commentElement.InnerText = string.Format("Comment for {0}", item.RenameValue);
			dataElement.AppendChild(valueElement);
			dataElement.AppendChild(commentElement);

			resourceDocument.DocumentElement.AppendChild(dataElement);
			resourceDocument.Save(System.IO.Path.Combine(ProjectRootPath, selectedResource.Name));
		}

		private void btnCreateResource_Click(object sender, RoutedEventArgs e)
		{
			if (DataContext != null && (DataContext is Common.Entities.DetailedProjectInfo))
			{
				Views.CreateResourceFileWindow wind = new CreateResourceFileWindow((DataContext as Common.Entities.DetailedProjectInfo).ProjectRootPath,
					(DataContext as Common.Entities.DetailedProjectInfo).RootNamespace);
				wind.Owner = this;
				wind.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
				if (wind.ShowDialog() == true)
				{
					Common.Entities.EmbeddedResources res = new Common.Entities.EmbeddedResources();
					res.Name = string.Format(@"Properties\{0}", System.IO.Path.GetFileName(wind.CreatedResourceFilePath));
					res.Generator = "ResXFileCodeGenerator";
					res.LastGenOutput = string.Format("{0}.Designer.cs", System.IO.Path.GetFileNameWithoutExtension(wind.CreatedResourceFilePath));
					List<Common.Entities.EmbeddedResources> resources = (cmbResourceFile.ItemsSource as List<Common.Entities.EmbeddedResources>);
					if (resources != null)
						resources.Add(res);

					cmbResourceFile.ItemsSource = null;
					cmbResourceFile.ItemsSource = resources;
				}
			}
		}
	}
}
